<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>File Picker Demo</title>
    <style>
      body {
        font-size: 14px;
      }
      group {
        display: flex;
        flex-flow: row wrap;
      }
      group + group {
        border-top: 1px solid #ccc;
      }
      line {
        width: 100%;
        padding: 10px;
        padding-top: 0;
      }
      part {
        padding: 0 10px;
        margin: 10px 0;
        align-content: center;
      }
      part + part {
        border-left: 1px solid #ccc;
      }
      input[type="text"] {
        outline: none;
        width: 80px;
      }
      #selected {
        cursor: default;
      }
      #selected.dragenter {
        background-color: #67c23a;
      }
    </style>
  </head>
  <body>
    <!-- 选择文件 -->
    <group>
      <part>
        <button id="openFile">
          <ruby>选择文件<rt>showOpenFilePicker</rt></ruby>
        </button>
      </part>
      <part>
        <input id="openMultiple" type="checkbox" checked />
        <label for="openMultiple">
          <ruby>多选<rt>multiple</rt></ruby>
        </label>
      </part>
      <part>
        <label for="openAccept">
          <ruby>类型<rt>accept</rt></ruby>
        </label>
        <input id="openAccept" type="text" value=".txt" />
      </part>
      <part>
        <label>
          <ruby>初始目录<rt>startIn</rt></ruby>
        </label>
        <start-in id="openStartIn" value="downloads"></start-in>
      </part>
    </group>

    <!-- 保存文件 -->
    <group>
      <part>
        <button id="saveFile">
          <ruby>保存文件<rt>showSaveFilePicker</rt></ruby>
        </button>
      </part>
      <part>
        <label for="suggestedName">
          <ruby>文件名<rt>suggestedName</rt></ruby>
        </label>
        <input id="suggestedName" type="text" value="out.txt" />
      </part>
      <part>
        <label for="saveAccept">
          <ruby>类型<rt>accept</rt></ruby>
        </label>
        <input id="saveAccept" type="text" value=".txt" />
      </part>
      <part>
        <label>
          <ruby>初始目录<rt>startIn</rt></ruby>
        </label>
        <start-in id="saveStartIn" value="downloads"></start-in>
      </part>
    </group>

    <!-- 选择目录 -->
    <group>
      <part>
        <button id="openDirectory">
          <ruby>选择目录<rt>showDirectoryPicker</rt></ruby>
        </button>
      </part>
      <part>
        <label for="openDirectoryDesc">
          <ruby>标题<rt>openDirectoryDesc</rt></ruby>
        </label>
        <input id="openDirectoryDesc" type="text" value="选择目录" />
      </part>
      <part>
        <label>
          <ruby>初始目录<rt>startIn</rt></ruby>
        </label>
        <start-in id="openDirectoryStartIn" value="downloads"></start-in>
      </part>
    </group>

    <!-- 文件选择组件 -->
    <group>
      <part><label>文件选择组件</label></part>
      <part>
        <input
          type="radio"
          id="showOpenFilePicker"
          name="type"
          value="showOpenFilePicker"
          checked
        />
        <label for="showOpenFilePicker">选择文件</label>
        <input type="radio" id="showSaveFilePicker" name="type" value="showSaveFilePicker" />
        <label for="showSaveFilePicker">保存文件</label>
        <input type="radio" id="showDirectoryPicker" name="type" value="showDirectoryPicker" />
        <label for="showDirectoryPicker">选择目录</label>
      </part>
      <line>
        <input
          id="selected"
          type="text"
          placeholder="拖放文件或目录到这里"
          readonly
          style="width: 400px"
        />
        <button id="button">浏览...</button>
      </line>
    </group>

    <script type="module">
      import filePicker from "./filePicker.js";
      const fs = require("fs");

      const $ = (s) => document.querySelector(s);
      const $$ = (s) => document.querySelectorAll(s);

      // 选择文件
      $("#openFile").addEventListener("click", () => {
        filePicker
          .showOpenFilePicker({
            multiple: $("#openMultiple").checked,
            accept: $("#openAccept").value,
            startIn: $("#openStartIn").value,
          })
          .then((files) => {
            alert(files.map((file) => file.path).join("\n"));
          })
          .catch(() => {});
      });

      // 保存文件
      $("#saveFile").addEventListener("click", () => {
        filePicker
          .showSaveFilePicker({
            suggestedName: $("#suggestedName").value,
            accept: $("#saveAccept").value,
            startIn: $("#saveStartIn").value,
          })
          .then((files) => {
            alert(files.map((file) => file.path).join("\n"));
          })
          .catch(() => {});
      });

      // 选择目录
      $("#openDirectory").addEventListener("click", () => {
        filePicker
          .showDirectoryPicker({
            openDirectoryDesc: $("#openDirectoryDesc").value,
            startIn: $("#openDirectoryStartIn").value,
          })
          .then((files) => {
            alert(files.map((file) => file.path).join("\n"));
          })
          .catch(() => {});
      });

      // 文件选择组件
      const $selected = $("#selected");
      function getType() {
        return [...$$('[name="type"]')].find((radio) => radio.checked).value;
      }
      $("#button").addEventListener("click", () => {
        const type = getType();
        let dialog;
        if (type === "showOpenFilePicker") {
          dialog = filePicker.showOpenFilePicker({
            multiple: $("#openMultiple").checked,
            accept: $("#openAccept").value,
            startIn: $("#openStartIn").value,
          });
        } else if (type === "showSaveFilePicker") {
          dialog = filePicker.showSaveFilePicker({
            suggestedName: $("#suggestedName").value,
            accept: $("#saveAccept").value,
            startIn: $("#saveStartIn").value,
          });
        } else if (type === "showDirectoryPicker") {
          dialog = filePicker.showDirectoryPicker({
            openDirectoryDesc: $("#openDirectoryDesc").value,
            startIn: $("#openDirectoryStartIn").value,
          });
        }
        dialog
          .then((files) => {
            $selected.value = files.map((file) => file.path).join(";");
            alert("选择：\n" + files.map((file) => file.path).join("\n"));
          })
          .catch(() => {
            $selected.value = "";
          });
      });

      const preventDefault = (e) => {
        e.preventDefault();
        e.stopPropagation();
        return false;
      };
      window.addEventListener("dragenter", preventDefault);
      window.addEventListener("dragover", preventDefault);
      window.addEventListener("dragleave", preventDefault);
      window.addEventListener("drop", preventDefault);
      $selected.addEventListener("dragenter", () => $selected.classList.add("dragenter"));
      $selected.addEventListener("dragleave", () => $selected.classList.remove("dragenter"));
      $selected.addEventListener("drop", (e) => {
        $selected.classList.remove("dragenter");
        const type = getType();
        const isOpenFile = type === "showOpenFilePicker";
        const isSaveFile = type === "showSaveFilePicker";
        const isDirectory = type === "showDirectoryPicker";
        const accept = isDirectory ? "" : $(isOpenFile ? "#openAccept" : "#saveAccept").value;
        const acceptPattern = new RegExp(
          //注：只支持“.jpg,.png”格式，不支持“image/*”格式
          accept.replace(/\s/g, "").replace(/\./g, "\\.").replace(/,/g, "|") + "$",
          "i"
        );
        let files = [...e.dataTransfer.files].filter((file) => {
          // 文件或目录
          if (isDirectory && fs.statSync(file.path).isFile()) return false;
          // 文件类型
          if (!isDirectory && !acceptPattern.test(file.name)) return false;
          return true;
        });
        // 单选或多选
        if (!isOpenFile || !$("#openMultiple").checked) files = files.slice(0, 1);
        $selected.value = files.map((file) => file.path).join(";");
        alert("拖放：\n" + files.map((file) => file.path).join("\n"));
      });
      $selected.addEventListener("click", () => {
        const files = $selected.value.split(";");
        alert(files.join("\n"));
      });
    </script>

    <!-- start-in 组件 -->
    <script>
      class StartIn extends HTMLElement {
        #select;
        constructor() {
          super();
          this.attachShadow({ mode: "open" });
          this.shadowRoot.innerHTML =
            `<select>` +
            ["desktop", "documents", "downloads", "music", "pictures", "videos"]
              .map((v) => `<option value="${v}">${v}</option>`)
              .join("") +
            `</select>`;
          this.#select = this.shadowRoot.querySelector("select");
          this.#select.value = this.value;
          this.#select.onchange = () => (this.value = this.#select.value);
        }
        get value() {
          return this.getAttribute("value") || "";
        }
        set value(value) {
          this.setAttribute("value", value);
        }
      }
      customElements.define("start-in", StartIn);
    </script>
  </body>
</html>
